#include "myiodevice.h"
#include <QDebug>
#include <QDir>
#include <QFuture>
#include <QtConcurrent>
#include "utils/signalcenter.h"
#include "utils/util.h"
using SampleType = float;
MyIODevice::MyIODevice(QObject *parent)
    : QIODevice(parent)
    , emitSign(false)
    , zeroCount(0)
{
    //打开文件的耗时操作需要使用异步的方式
    QFuture<bool> future = QtConcurrent::run(std::bind(&MyIODevice::openFile, this));
}

MyIODevice::~MyIODevice()
{
    inputFile.close();
}

void MyIODevice::start()
{
    if (!inputFile.isOpen()) {
        inputFile.open(QIODevice::ReadOnly);
    }

    if (!isOpen()) {
        qDebug() << "XIODevice is opening!";
        // 关键: 通过 QIODevice 的 open 函数将其标记为已打开
        open(QIODevice::ReadOnly);
    } else {
        qDebug() << "XIODevice is already open!";
    }

    // 记录 QIODevice 是否已正确打开
    if (isOpen()) {
        qDebug() << "XIODevice is now open!";
    } else {
        qDebug() << "Error: XIODevice failed to open!";
    }
}

void MyIODevice::stop()
{
    if (inputFile.isOpen()) {
        qDebug() << "文件已关闭";
        inputFile.close();
    }

    QIODevice::close();
}

/**
 * @brief MyIODevice::readData  这个函数是QAudioSink当需要更多的数据时自动调用的函数，我们需要处理的逻辑就是读取参数
 * 提供的大小的数据，并存放在data中。然后返回读取的数据的大小
 * 
 * @param data   数据的内存缓冲区
 * @param maxSize   读取的最大的大小
 * @return 
 */
qint64 MyIODevice::readData(char *data, qint64 maxSize)
{
    if (!inputFile.isOpen()) {
        qWarning() << "文件未打开，无法读取数据";
        return 0;
    }

    qint64 bytesRead = inputFile.read(data, maxSize);
    if (bytesRead == -1) {
        qWarning() << "读取文件出错：" << inputFile.errorString();
        return 0;
    }

    globalThreadPool->start(std::bind(&MyIODevice::computeAudioData, this, data, bytesRead));

    return bytesRead;
}

qint64 MyIODevice::writeData(const char *data, qint64 maxSize)
{
    Q_UNUSED(data);
    Q_UNUSED(maxSize);
    return 0; // 不支持写入
}

/**
 * @brief MyIODevice::bytesAvailable 必须要重写这个函数，QAudioSink才会去调用readData函数。
 * QAudioSink 依赖于 QIODevice::bytesAvailable() 的返回值来决定是否需要请求数据。如果 bytesAvailable() 返回 0，
 * QAudioSink 不会调用 readData()，也不会从 IdleState 切换到 ActiveState。
 *    默认情况下，QIODevice::bytesAvailable() 返回 0，除非你重载了它！
 * @return 
 */
qint64 MyIODevice::bytesAvailable() const
{
    qint64 availableBytes = inputFile.bytesAvailable() + QIODevice::bytesAvailable();
    qDebug() << "XIODevice bytesAvailable:" << availableBytes;
    if (availableBytes == 0 && zeroCount > 4) {
        emit SignalCenter::instance().audioPlayFinshed();
        zeroCount = 0;
    } else if (availableBytes == 0)
        zeroCount++;
    else if (availableBytes != 0)
        zeroCount = 0;
    return availableBytes;
}

void MyIODevice::computeAudioData(char *data, qint64 bytesRead)
{
    qDebug() << "Read" << bytesRead << "bytes from file at"
             << QDateTime::currentDateTime().toString("hh:mm:ss.zzz");

    const SampleType *samples = reinterpret_cast<const SampleType *>(data);
    int totalSamples = bytesRead / sizeof(SampleType); // 样本总数
    int frameCount = totalSamples / 2;                 // 每帧包含 2 个声道的样本
    // qDebug() << "totalSamples count: " << totalSamples;
    // 3. 统计左右声道的音量数据
    double sumSquareLeft = 0.0;
    double sumSquareRight = 0.0;
    SampleType peakLeft = 0.0f;
    SampleType peakRight = 0.0f;

    // 4. 遍历所有的帧，计算左声道和右声道的 RMS 和峰值
    for (int i = 0; i < frameCount; ++i) {
        SampleType leftSample = std::clamp(samples[2 * i], -1.0f, 1.0f);      // 左声道
        SampleType rightSample = std::clamp(samples[2 * i + 1], -1.0f, 1.0f); // 右声道

        // 计算左声道的RMS和峰值
        sumSquareLeft += leftSample * leftSample;            // 平方和
        peakLeft = std::max(peakLeft, std::abs(leftSample)); // 取样本的绝对最大值

        // 计算右声道的RMS和峰值
        sumSquareRight += rightSample * rightSample;
        peakRight = std::max(peakRight, std::abs(rightSample));
    }

    // 5. 计算 RMS (均方根)，如果数据出错的话，RMS 可能为 0，如果样本中全部是 0，log10(0) 会产生 -inf (负无穷大)。
    //因此需要设定一个最小值是0.00001
    double rmsLeft = std::max(0.00001, std::sqrt(sumSquareLeft / frameCount));
    double rmsRight = std::max(0.00001, std::sqrt(sumSquareRight / frameCount));

    // 6. 计算 dBFS（参考值为 1.0）
    double dBFSLeft = 20.0 * std::log10(rmsLeft);
    double dBFSRight = 20.0 * std::log10(rmsRight);

    //合并dBFS和RMS
    double avgRMS = (rmsLeft + rmsRight) / 2.0;
    double avgdBFS = (dBFSLeft + dBFSRight) / 2.0;
    // 7. 打印音量数据
    qDebug() << "Left Peak:" << peakLeft << "Right Peak:" << peakRight << "RMS Left:" << rmsLeft
             << "RMS Right:" << rmsRight << "dBFS Left:" << dBFSLeft << "dBFS Right:" << dBFSRight;
    float Value = std::clamp(static_cast<int>((1 + avgdBFS / 60.0) * 100), 0, 100);
    if (Value > 0 && emitSign) {
        emit SignalCenter::instance().audioDataComputeCompleted(Value, OUTPUTLEVEL);
        emitSign = false;
    } else {
        emit SignalCenter::instance().clearProBarVolume(OUTPUTLEVEL);
        emitSign = true;
    }
    Q_UNUSED(avgRMS);
}

bool MyIODevice::openFile()
{
    inputFile.setFileName(
        QDir::toNativeSeparators("F:/workspace/QtPorject/AikeMetting/resources/wenrou.pcm"));
    if (!inputFile.open(QIODevice::ReadOnly)) {
        qWarning() << "文件打开失败，错误原因：" << inputFile.errorString();
        return false;
    } else {
        qDebug() << "文件打开成功，文件大小：" << inputFile.size() << "字节";
        return true;
    }
}
